// G15SysInfo.mm : implementation file
// (c) 2009 Alexandre d'Alton


#include "G15SysInfo.h"
#include "MenuMeterCPUStats.h"
#include "MenuMeterMemStats.h"
#include "MenuMeterNetStats.h"

#include <vector>
#include <unistd.h>
#include <time.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

MenuMeterCPUStats * theCPUInfo;
MenuMeterMemStats * theMemInfo;
MenuMeterNetStats * theNetInfo;

Boolean G15SysInfo::OnInitDialog()
{
    m_currentHighlightPosition = 1;
    
    theCPUInfo = [[MenuMeterCPUStats alloc] init];
	theMemInfo = [[MenuMeterMemStats alloc] init];
    theNetInfo = [[MenuMeterNetStats alloc] init];
	
    int hRes = m_lcd.Initialize((CFStringRef)@"System Monitor", LG_DUAL_MODE, FALSE, TRUE);

    if (hRes != S_OK)
    {
        // Something went wrong, when connecting to the LCD Manager software. Deal with it...
        return FALSE;
    }

    m_lcd.ModifyDisplay(LG_MONOCHROME);
    m_lcd.ModifyControlsOnPage(0);
    m_lcd.ShowPage(0);
    m_lcd.SetAsForeground(TRUE);
    InitLCDObjectsMonochrome();

    return TRUE;  // return TRUE  unless you set the focus to a control
}


void G15SysInfo::OnTimer()
{
    
    CheckButtonPresses();
    
    m_lcd.Update();

}

void G15SysInfo::InitLCDObjectsMonochrome()
{
    m_lcd.ModifyDisplay(LG_MONOCHROME);
	
    /***************/
    /* FIRST PAGE */
    /***************/

#define FONT_SZ 10

    m_smallText1 = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSLeftTextAlignment, 70);
    m_lcd.SetOrigin(m_smallText1, 0, 2*FONT_SZ);
    m_lcd.SetText(m_smallText1, (CFStringRef)(@"C"));

    m_smallText2 = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSLeftTextAlignment, 70);
    m_lcd.SetOrigin(m_smallText2, 0, 3*FONT_SZ);
    m_lcd.SetText(m_smallText2, (CFStringRef)(@"M"));
	
    m_song = m_lcd.AddText(LG_SCROLLING_TEXT, LG_TINY, NSLeftTextAlignment, 160);
    m_lcd.SetOrigin(m_song, 0, 1*FONT_SZ);

	m_temp = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSRightTextAlignment, 80);
    m_lcd.SetOrigin(m_temp, 80, 2*FONT_SZ);
    m_lcd.SetText(m_temp, (CFStringRef)(@"temp"));
	
    m_time = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSLeftTextAlignment/*DT_CENTER*/, LGLCD_BW_BMP_WIDTH);
    m_lcd.SetOrigin(m_time, 0, 0);
	
    m_date = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSRightTextAlignment/*DT_CENTER*/, LGLCD_BW_BMP_WIDTH);
    m_lcd.SetOrigin(m_date, 0, 0);
	
    m_nin = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSRightTextAlignment/*DT_CENTER*/, 27);
    m_lcd.SetOrigin(m_nin, 68+43, 2*FONT_SZ);
    m_nil = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSLeftTextAlignment/*DT_CENTER*/, 8);
    m_lcd.SetOrigin(m_nil, 68+35, 2*FONT_SZ);
    m_lcd.SetText(m_nil, (CFStringRef)(@"i:"));
	
    m_nout = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSRightTextAlignment/*DT_CENTER*/, 26);
    m_lcd.SetOrigin(m_nout, 68+9, 2*FONT_SZ);
    m_nol = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSLeftTextAlignment/*DT_CENTER*/, 9);
    m_lcd.SetOrigin(m_nol, 68+0, 2*FONT_SZ);
    m_lcd.SetText(m_nol, (CFStringRef)(@"o:"));
	
	m_tout = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSRightTextAlignment/*DT_CENTER*/, 35);
    m_lcd.SetOrigin(m_tout, 68, 3*FONT_SZ);
    m_tin = m_lcd.AddText(LG_STATIC_TEXT, LG_TINY, NSRightTextAlignment/*DT_CENTER*/, 35);
    m_lcd.SetOrigin(m_tin, 68+35, 3*FONT_SZ);
    
    m_cpu = m_lcd.AddProgressBar(LG_FILLED);
    m_lcd.SetProgressBarSize(m_cpu, 60, 8);
    m_lcd.SetOrigin(m_cpu, 8, 2*FONT_SZ+1);

    m_mem = m_lcd.AddProgressBar(LG_FILLED);
    m_lcd.SetProgressBarSize(m_mem, 60, 8);
    m_lcd.SetOrigin(m_mem, 8, 3*FONT_SZ+1);
    
	
    m_right1 = m_lcd.AddIcon([NSImage imageNamed:@"next.ico"], 16, 16);//next.ico
    m_lcd.SetOrigin(m_right1, 142, 35);
	

    /***************/
    /* SECOND PAGE */
    /***************/
    m_lcd.AddNewPage();
    m_lcd.ModifyControlsOnPage(1);

    m_progressbar1 = m_lcd.AddProgressBar(LG_DOT_CURSOR);
    m_lcd.SetProgressBarSize(m_progressbar1, 90, 5);
    m_lcd.SetOrigin(m_progressbar1, 70, 0);
    
        
    m_progressbar2 = m_lcd.AddProgressBar(LG_FILLED);
    m_lcd.SetProgressBarSize(m_progressbar2, 60, 8);
    m_lcd.SetOrigin(m_progressbar2, 70, 10);

    m_progressbar3 = m_lcd.AddProgressBar(LG_CURSOR);
    m_lcd.SetProgressBarSize(m_progressbar3, 30, 3);
    m_lcd.SetOrigin(m_progressbar3, 70, 25);

    NSImage* logoBitmap_ = [NSImage imageNamed:@"logitech_logo.png"];
    m_logo = m_lcd.AddBitmap(55, 43);
    m_lcd.SetBitmap(m_logo, logoBitmap_);
    m_lcd.SetOrigin(m_logo, 0, 0);
     
    m_right2 = m_lcd.AddIcon([NSImage imageNamed:@"next.ico"], 16, 16);
    m_lcd.SetOrigin(m_right2, 142, 35);
}

void G15SysInfo::CheckButtonPresses()
{
	static time_t old_time = 0;
	
	time_t t = time(NULL);
	
	if (t - old_time) {
		cpuUpdate();
		itunesUpdate();
		netWorkUpdate();
		old_time = t;
	}
    CheckbuttonPressesMonochrome();
}

char timebuf[254];
char loadbuf[254];
char membuf[254];
char tempbuf[254];

void G15SysInfo::formatNumber(char * str, unsigned long long value) {
	int zeros = 1+ (int) log10((double)value);
	char * format;
	char fmt[6];
	char unit = 'b';
	float div;
	
	if (value == 0) {
		sprintf(str, "0");
		return;
	}
	
	switch (zeros % 3) {
		case 1:
			format = "%1.2f";
			break;
		case 2:
			format = "%2.1f";
			break;
		case 0:
			format = "%3.0f";
			break;
	}
	
	unit = zeros <= 3 ? 'b' : zeros <= 6 ? 'k' : zeros <= 9 ? 'M' : zeros <= 12 ? 'G' : 'T'; 
	div = zeros <= 3 ? 1 : zeros <= 6 ? 1E3 : zeros <= 9 ? 1E6 : zeros <= 12 ? 1E9 : 1E12;
	
	sprintf(fmt, "%s%c", format, unit);
	sprintf(str, fmt, (float) value / div);
	return;
}

void G15SysInfo::netWorkUpdate() {
	NSDictionary *netInfo;
	netInfo = [theNetInfo getNetData:1.0];

	/** TODO: Interface should be retrieved from the configuration interface.... */
	NSDictionary * ifInfo = [netInfo objectForKey:@"en1"];  
	
	unsigned long int in = [[ifInfo objectForKey:@"deltain"] unsignedLongValue];
	unsigned long int out = [[ifInfo objectForKey:@"deltaout"] unsignedLongValue];

	formatNumber(tempbuf, in);
	m_lcd.SetText(m_nin, __CFStringMakeConstantString(tempbuf));
	
	formatNumber(tempbuf, out);
	m_lcd.SetText(m_nout, __CFStringMakeConstantString(tempbuf));

	unsigned long long tin = [[ifInfo objectForKey:@"totalin"] unsignedLongLongValue];
	unsigned long long tout = [[ifInfo objectForKey:@"totalout"] unsignedLongLongValue];
	
	formatNumber(tempbuf, tin);
	m_lcd.SetText(m_tin, __CFStringMakeConstantString(tempbuf));
	
	formatNumber(tempbuf, tout);
	m_lcd.SetText(m_tout, __CFStringMakeConstantString(tempbuf));
	
}

void G15SysInfo::itunesUpdate()
{
	NSString *sourceScript = [NSString stringWithFormat:@"tell application \"iTunes\"\n return name of current track & \"-\" & artist of current track\n end tell"];
	NSAppleScript *script = [[NSAppleScript alloc] init];
	NSDictionary *reponse = nil;
	NSAppleEventDescriptor *result;

	[script initWithSource:sourceScript];
	[script compileAndReturnError:nil];

	result = [script executeAndReturnError:&reponse];

	if ([[result stringValue] length] > 0) {
		[[result stringValue] getCString:tempbuf]; 
		m_lcd.SetText(m_song, __CFStringMakeConstantString(tempbuf));
	}
}

void G15SysInfo::cpuUpdate() {
	int proccount;
	int i;
	double system, nice, user, total = 0;
	double used, free;
	NSArray * currentLoad = nil;
	NSDictionary * procLoad;
	NSDictionary * mem;
	time_t t = 	time(NULL);
	struct tm tm;

	localtime_r(&t, &tm);
	strftime(timebuf, 254, "%T", &tm);
	m_lcd.SetText(m_time, __CFStringMakeConstantString(timebuf));
	strftime(timebuf, 254, "%D", &tm);
	m_lcd.SetText(m_date, __CFStringMakeConstantString(timebuf));
	currentLoad = [theCPUInfo currentLoad:0];
	
	proccount = [currentLoad count];
	for ( i = 0; i < proccount; i++) {
		procLoad = [currentLoad objectAtIndex:i];
		if (procLoad) {
			system = [(NSNumber *)[procLoad objectForKey:@"system"] doubleValue];
			user = [(NSNumber *)[procLoad objectForKey:@"user"] doubleValue];
			nice = [(NSNumber *)[procLoad objectForKey:@"nice"] doubleValue];
			total += system + user + nice;
		}
	}
	sprintf(loadbuf, "%03d", (int) (total * 100 / 2));
	m_lcd.SetProgressBarPosition(m_cpu, static_cast<float>((int) (total * 100 / 2)));
	
	mem = [theMemInfo getMemStats];
	used = [(NSNumber *)[mem objectForKey:@"used"] doubleValue];
	free = [(NSNumber *)[mem objectForKey:@"free"] doubleValue];
	sprintf(membuf, "%03d", (int) (100 * free / (free + used)));
	m_lcd.SetProgressBarPosition(m_mem, static_cast<float>((int) (100 * used / (free + used))));
	
	[[theCPUInfo currentTemp] getCString:tempbuf];
	tempbuf[2] = 'C';
	tempbuf[3] = '\0';
	
	m_lcd.SetText(m_temp, __CFStringMakeConstantString(tempbuf));
	
}

void G15SysInfo::CheckbuttonPressesMonochrome()
{
    m_lcd.ModifyDisplay(LG_MONOCHROME);

    if (m_lcd.ButtonTriggered(LG_BUTTON_4))
    {
        m_lcd.ShowPage((m_lcd.GetCurrentPageNumber() + 1) % m_lcd.GetPageCount());
    }
}

